1
2
3
4 package joeq.Scheduler;
5
6 import joeq.Allocator.CodeAllocator;
7 import joeq.Class.PrimordialClassLoader;
8 import joeq.Class.jq_Class;
9 import joeq.Class.jq_InstanceMethod;
10 import joeq.Memory.CodeAddress;
11 import joeq.Memory.HeapAddress;
12 import joeq.Memory.StackAddress;
13 import joeq.Runtime.Debug;
14 import joeq.Runtime.SystemInterface;
15 import joeq.Runtime.Unsafe;
16 import jwutil.util.Assert;
17
18
19
20
21
22 public class jq_InterrupterThread extends Thread {
23
24 public static
25 public static final boolean STATISTICS = true;
26
27 jq_InterrupterThread(jq_NativeThread other_nt) {
28 this.other_nt = other_nt;
29 if (TRACE)
30 SystemInterface.debugwriteln(
31 "Initialized timer interrupt for native thread " + other_nt);
32 myself = ThreadUtils.getJQThread(this);
33 myself.disableThreadSwitch();
34 this.tid =
35 SystemInterface.create_thread(
36 _run.getDefaultCompiledVersion().getEntrypoint(),
37 HeapAddress.addressOf(this));
38 jq_NativeThread my_nt = new jq_NativeThread(myself);
39 my_nt.getCodeAllocator().init();
40 my_nt.getHeapAllocator().init();
41
42 SystemInterface.resume_thread(this.tid);
43 }
44
45
46 private int tid, pid;
47 private jq_NativeThread other_nt;
48 private jq_Thread myself;
49
50
51 private int enabledCount;
52 private int disabledCount;
53
54 public void dumpStatistics() {
55 Debug.write("enabled=");
56 Debug.write(enabledCount);
57 Debug.write(" disabled=");
58 Debug.writeln(disabledCount);
59 }
60
61 public static int QUANTA = 10;
62
63 public void run() {
64 this.pid = SystemInterface.init_thread();
65 Unsafe.setThreadBlock(this.myself);
66
67 SystemInterface.set_thread_priority(this.tid, SystemInterface.THREAD_PRIORITY_TIME_CRITICAL);
68 for (;;) {
69 SystemInterface.msleep(QUANTA);
70 other_nt.suspend();
71
72 jq_Thread javaThread = other_nt.getCurrentJavaThread();
73 if (javaThread.isThreadSwitchEnabled()) {
74 if (STATISTICS) ++enabledCount;
75 if (TRACE)
76 SystemInterface.debugwriteln(
77 "TICK! " + other_nt + " Java Thread = " + javaThread);
78 javaThread.disableThreadSwitch();
79 Assert._assert(other_nt.getCurrentJavaThread() == javaThread);
80 jq_RegisterState regs = javaThread.getRegisterState();
81 regs.setContextFlags(
82 jq_RegisterState.CONTEXT_CONTROL
83 | jq_RegisterState.CONTEXT_INTEGER
84 | jq_RegisterState.CONTEXT_FLOATING_POINT);
85 boolean b = other_nt.getContext(regs);
86 if (!b) {
87 if (TRACE)
88 SystemInterface.debugwriteln(
89 "Failed to get thread context for " + other_nt);
90 } else {
91 if (TRACE)
92 SystemInterface.debugwriteln(
93 other_nt
94 + " : "
95 + javaThread
96 + " ip="
97 + regs.getEip().stringRep()
98 + " sp="
99 + regs.getEsp().stringRep()
100 + " cc="
101 + CodeAllocator.getCodeContaining(regs.getEip()));
102
103 regs.setEsp(
104 (StackAddress) regs.getEsp().offset(
105 -HeapAddress.size()));
106 regs.getEsp().poke(HeapAddress.addressOf(other_nt));
107 regs.setEsp(
108 (StackAddress) regs.getEsp().offset(
109 -CodeAddress.size()));
110 regs.getEsp().poke(regs.getEip());
111 regs.setEip(
112 jq_NativeThread
113 ._threadSwitch
114 .getDefaultCompiledVersion()
115 .getEntrypoint());
116 regs.setContextFlags(jq_RegisterState.CONTEXT_CONTROL);
117 b = other_nt.setContext(regs);
118 if (!b) {
119 if (TRACE)
120 SystemInterface.debugwriteln(
121 "Failed to set thread context for " + other_nt);
122 } else {
123 if (TRACE)
124 SystemInterface.debugwriteln(
125 other_nt
126 + " : simulating a call to threadSwitch");
127 }
128 }
129 } else {
130
131 if (STATISTICS) ++disabledCount;
132
133 }
134 other_nt.resume();
135 }
136 }
137
138 public static final jq_Class _class;
139 public static final jq_InstanceMethod _run;
140 static {
141 _class =
142 (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType(
143 "Ljoeq/Scheduler/jq_InterrupterThread;");
144 _run = _class.getOrCreateInstanceMethod("run", "()V");
145 }
146 }